﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using HtmlAgilityPack;

namespace Zpovednice
{
    public class ZpovedniceAPI
    {
        private const string ZpovedniceUri = @"http://www.zpovednice.cz/";
        private const string LoginUri = ZpovedniceUri + @"logon.php?nick={0}&heslo={1}&send=true";
        private const string ConfessionListUri = ZpovedniceUri + @"index.php?pocet={0}&orderby={1}";
        private const string ConfessionDetailUri = ZpovedniceUri + @"detail.php?statusik={0}";
        private const string SendAbsolutionRefererUri = ZpovedniceUri + @"souhlasr.php";
        private const string SendAbsolutionUri = ZpovedniceUri + @"kontrolr.php";
        private const string SendPersonalMessageUri = ZpovedniceUri + @"kontrolk.php";
        private const string SendPersonalMessageRefererUri = ZpovedniceUri + @"profil.php?kdo={0}";
        private const string ProfileDetailUri = ZpovedniceUri + @"profil.php?kdo={0}";
        private const string DeletePersonalMessageUri = ZpovedniceUri + @"deletek.php?jo={0}";

        private static Encoding DefaultEncoding = Encoding.GetEncoding("windows-1250");


    
        private CookieContainer CookieContainer { get; set; }

        public Profile LoggedUser { get; private set; }
        public bool LoggedIn { get { return LoggedUser != null; } }

        public LoginResult Login(string username, string password)
        {
            Uri loginUri = new Uri(string.Format(LoginUri, username, password));
            HttpWebRequest loginRequest = (HttpWebRequest)WebRequest.Create(loginUri);
            CookieContainer = new CookieContainer();
            loginRequest.AllowAutoRedirect = false;
            loginRequest.CookieContainer = CookieContainer;
            HttpWebResponse loginResponse = (HttpWebResponse)loginRequest.GetResponse();
            loginResponse.Close();

            LoggedUser = new Profile();
            LoggedUser.Id = int.Parse(CookieContainer.GetCookies(new Uri(LoginUri))["kdojeto"].Value);
            LoggedUser.Name = username;
            LoggedUser.Password = password;

            return LoginResult.Sucess;
        }

        public List<Confession> GetConfessionList(OrderType order = OrderType.Id, ConfessionCategories category = ConfessionCategories.All, int count = 20)
        {
            string orderString;
            switch (order)
            {
                case OrderType.LastActivity: orderString = "pristup"; break;
                case OrderType.LastVisit: orderString = "rezerva"; break;
                default:
                case OrderType.Id: orderString = "ide"; break;
            }

            Uri listUri = new Uri(string.Format(ConfessionListUri, count, orderString));
            HttpWebRequest listRequest = (HttpWebRequest)WebRequest.Create(listUri);
            listRequest.CookieContainer = CookieContainer;

            List<Confession> confessions = new List<Confession>();

            HtmlDocument listPage = new HtmlDocument();
            listPage.Load(listRequest.GetResponse().GetResponseStream(), DefaultEncoding);

        
            foreach (var item in listPage.DocumentNode.SelectNodes("//div[@id='conflist']/ul"))
            {
                Confession confession = new Confession();
                confession.Id = int.Parse(item.SelectSingleNode("li[@class='c2']").InnerText);
                string absolutionsCountText = item.SelectSingleNode("li[@class='c5']").InnerText; // absolutions count

                bool wasVisited = string.IsNullOrEmpty(item.SelectSingleNode("li[@class='c6']").InnerHtml); // was visited
                bool neverVisited = (item.SelectSingleNode("li[@class='c6']").InnerHtml.Contains("grafika/zmarkn.gif"));


                if (wasVisited && absolutionsCountText.Contains(":"))
                {

                }
                else if (neverVisited)
                {
                    int realAbsolutionsCoutnt = int.Parse(absolutionsCountText);
                    confession.AbsolutionsCount = realAbsolutionsCoutnt;
                }

                confessions.Add(confession);
            }
            return confessions;
        }

        public Confession GetConfession(int id)
        {
            Uri uri = new Uri(string.Format(ConfessionDetailUri, id));
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
            request.CookieContainer = CookieContainer;

            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            HtmlDocument doc = new HtmlDocument();
            doc.Load(response.GetResponseStream(), DefaultEncoding);

            Confession confession = new Confession();
            confession.Id = id;
            if (doc.DocumentNode.SelectSingleNode("//td[@class='confheader']") != null)
            {
                confession.IsDeleted = false;
                confession.Name = doc.DocumentNode.SelectSingleNode("//td[@class='confheader']").InnerText.Trim();
                confession.Text = doc.DocumentNode.SelectSingleNode("//td[@class='conftext']").InnerText.Trim();

                string tempConfessionDate = Regex.Match(doc.DocumentNode.SelectSingleNode("//td[@class='boxheader']").InnerText, @".*  č\.[0-9]*, vloženo  (.*) ").Groups[1].Value;
                confession.CreationDate = DateTime.ParseExact(tempConfessionDate.Trim(), "dd.MM.yyyy HH:mm:ss", CultureInfo.InvariantCulture);

                string confessionType = Regex.Match(doc.DocumentNode.SelectSingleNode("//td[@class='boxheader']").InnerText, @"(.*)  č\.[0-9]*, vloženo  .* ").Groups[1].Value;

                switch (confessionType)
                {
                    case "Zpověď": confession.Category = ConfessionCategories.Confession; break;
                    case "Diskuze": confession.Category = ConfessionCategories.Discussion; break;
                    case "Neprofesionální umělecká Tvorba": confession.Category = ConfessionCategories.Creation; break;
                    case "Otázky - Vzkazy": confession.Category = ConfessionCategories.Question; break;
                }

                string confAuthorName;
                int? confAuthorID = null;
                if (doc.DocumentNode.SelectSingleNode("//td[@class='conftext']//span[@class='signunreg']") != null) // anonymouse author
                {
                    confAuthorName = doc.DocumentNode.SelectSingleNode("//td[@class='conftext']//span[@class='signunreg']").InnerText.Replace(@"&nbsp;", string.Empty);
                }
                else
                {
                    confAuthorName = doc.DocumentNode.SelectSingleNode("//td[@class='conftext']//td[@class='signinfo']//a").InnerText;
                    string tempConfessionAuthorName = Regex.Match(doc.DocumentNode.SelectSingleNode("//td[@class='conftext']//td[@class='signinfo']//a").Attributes["href"].Value, @"profil\.php\?kdo=([0-9]*).?").Groups[1].Value;
                    confAuthorID = int.Parse(tempConfessionAuthorName);
                }

                Gender confessionAuthorGender = Gender.Unknown;
                int? confessionAuthorAge = null;
                if (doc.DocumentNode.SelectSingleNode("//td[@class='conftext']//td[@class='signinfo']//img") != null)
                {
                    if (doc.DocumentNode.SelectSingleNode("//td[@class='conftext']//td[@class='signinfo']//img[@src='grafika/femaleh.gif']") != null)
                        confessionAuthorGender = Gender.Female;
                    else if (doc.DocumentNode.SelectSingleNode("//td[@class='conftext']//td[@class='signinfo']//img[@src='grafika/maleh.gif']") != null)
                        confessionAuthorGender = Gender.Male;


                    int temp;
                    bool succ = false;
                    succ = int.TryParse(doc.DocumentNode.SelectSingleNode("//td[@class='conftext']//td[@class='signinfo'][count(img)>0]").ChildNodes[1].InnerText.Replace(@"&nbsp;", string.Empty), out temp);

                    if (!succ && doc.DocumentNode.SelectSingleNode("//td[@class='conftext']//td[@class='signinfo'][count(img)>0]").ChildNodes.Count > 2)
                        succ = int.TryParse(doc.DocumentNode.SelectSingleNode("//td[@class='conftext']//td[@class='signinfo'][count(img)>0]").ChildNodes[2].InnerText.Replace(@"&nbsp;", string.Empty), out temp);

                    if (!succ && doc.DocumentNode.SelectSingleNode("//td[@class='conftext']//td[@class='signinfo'][count(img)>0]").ChildNodes.Count > 3)
                        succ = int.TryParse(doc.DocumentNode.SelectSingleNode("//td[@class='conftext']//td[@class='signinfo'][count(img)>0]").ChildNodes[3].InnerText.Replace(@"&nbsp;", string.Empty), out temp);

                    if (!succ && doc.DocumentNode.SelectSingleNode("//td[@class='conftext']//td[@class='signinfo'][count(img)>0]").ChildNodes.Count > 4)
                        succ = int.TryParse(doc.DocumentNode.SelectSingleNode("//td[@class='conftext']//td[@class='signinfo'][count(img)>0]").ChildNodes[4].InnerText.Replace(@"&nbsp;", string.Empty), out temp);

                    if (succ)
                        confessionAuthorAge = temp;

                }
                confAuthorName = confAuthorName.Trim();

                confession.Creator = new Profile();
                confession.Creator.Id = confAuthorID;
                confession.Creator.Name = confAuthorName;
                confession.Creator.Gender = confessionAuthorGender;
                confession.Creator.Age = confessionAuthorAge;

                HtmlNode confessionsNode = doc.DocumentNode.SelectSingleNode("//table[5]/tr[2]/td/table");
                if (doc.DocumentNode.SelectNodes("//td[@class='sectlheader']") != null) // no absolutions?
                {
                    int absolutionsCount = (confessionsNode.SelectNodes("tr").Count - 1) / 3;
                    confession.AbsolutionsCount = absolutionsCount;

                    var absolutions = new List<Absolution>();
                    confession.Absolutions = absolutions;

                    var col = confessionsNode.SelectNodes("tr");
                    for (int j = 1; j <= (col.Count - 1) / 3; j++)
                    {
                        var absolution = new Absolution();
                        absolution.Confession = confession;


                        var date = col[3 * j - 2];//date
                        absolution.CreationDate = DateTime.ParseExact(date.InnerText.Trim(), "dd.MM.yyyy HH:mm:ss", CultureInfo.InvariantCulture);

                        var text = col[3 * j + 1 - 2];//text
                        absolution.Text = text.InnerText.Trim();

                        var absolutionAuthorNode = col[3 * j + 2 - 2].SelectSingleNode("td/table/tr");//author

                        int? absolutionAuthorID = null;
                        Gender absolutionAuthorSex = Gender.Unknown;
                        int? absolutionAuthorAge = null;
                        string absolutionAuthorName = null;
                        string smilieFaceText = null;

                        if (absolutionAuthorNode.SelectSingleNode("*/a") == null) // anonymouse author
                        {
                            absolutionAuthorName = absolutionAuthorNode.ChildNodes[1].InnerText.Replace(@"&nbsp;", string.Empty);
                            if (absolutionAuthorNode.ChildNodes[1].ChildNodes.Count > 1)
                            {
                                smilieFaceText = absolutionAuthorNode.ChildNodes[1].ChildNodes[1].Attributes["src"].Value;
                            }
                        }
                        else
                        {
                            absolutionAuthorID = int.Parse((absolutionAuthorNode.SelectSingleNode("*/a").Attributes["href"].Value.Replace("profil.php?kdo=", string.Empty)));
                            absolutionAuthorName = absolutionAuthorNode.SelectSingleNode("*/a").InnerText;
                            if (absolutionAuthorNode.ChildNodes[1].ChildNodes[1].Name == "img")
                            {
                                smilieFaceText = absolutionAuthorNode.ChildNodes[1].ChildNodes[1].Attributes["src"].Value;
                            }
                        }

                        Smiley absolutionSmiley = Smiley.None;
                        if (smilieFaceText != null)
                            absolutionSmiley = (Smiley)int.Parse(Regex.Match(smilieFaceText, "grafika/([0-9]*).gif").Groups[1].Value);

                        absolutionAuthorName = absolutionAuthorName.Trim();

                        if (absolutionAuthorNode.ChildNodes[3].ChildNodes.Count > 0)
                        {
                            string absolutionSexValue = absolutionAuthorNode.ChildNodes[3].ChildNodes[1].Attributes["src"].Value;

                            if (absolutionSexValue == "grafika/female.gif")
                                absolutionAuthorSex = Gender.Female;
                            else if (absolutionSexValue == "grafika/male.gif")
                                absolutionAuthorSex = Gender.Male;

                            if (absolutionAuthorNode.ChildNodes[3].ChildNodes[2].InnerText != @"&nbsp;")
                            {
                                int tempVal;
                                if (int.TryParse(absolutionAuthorNode.ChildNodes[3].ChildNodes[2].InnerText.Replace(@"&nbsp;", string.Empty), out tempVal))
                                {
                                    absolutionAuthorAge = tempVal;
                                }
                                else
                                {
                                    //absolutionAuthorAge = 0;
                                }
                            }
                        }

                        absolution.Creator = new Profile();
                        absolution.Creator.Id = absolutionAuthorID;
                        absolution.Creator.Name = absolutionAuthorName;
                        absolution.Creator.Gender = absolutionAuthorSex;
                        absolution.Creator.Age = absolutionAuthorAge;
                        absolution.Smiley = absolutionSmiley;


                        absolutions.Add(absolution);
                    }
                }
            }
            else
            {
                confession.IsDeleted = true;
            }



            return confession;
        }

        public void CreateConfession(string text, ConfessionCategories category)
        {
       

        }

        public void AddAbsolution(int confessionId, string text, Smiley smiley = Smiley.None)
        {
            if (!LoggedIn)
                throw new Exception("Not logged in");

            string postData = "jmenko=" + LoggedUser.Name;
            postData += ("&rozreseni=" + text.Replace(" ", "+"));
            postData += ("&sm=" + (int)smiley);
            postData += ("&ciselko=" + confessionId);
            postData += ("&hesloj=" + "");
            postData += ("&pop=" + "");
            postData += ("&code=" + "");
            postData += ("&pravidla=" + "1");

            byte[] data = DefaultEncoding.GetBytes(postData);


            HttpWebRequest sendAbsolutiosRequest = (HttpWebRequest)WebRequest.Create(new Uri(SendAbsolutionUri));
            sendAbsolutiosRequest.Referer = SendAbsolutionRefererUri;
            sendAbsolutiosRequest.Method = "POST";
            sendAbsolutiosRequest.ContentType = "application/x-www-form-urlencoded";
            sendAbsolutiosRequest.ContentLength = data.Length;
            sendAbsolutiosRequest.CookieContainer = CookieContainer;
            Stream newStream = sendAbsolutiosRequest.GetRequestStream();
            newStream.Write(data, 0, data.Length);
            newStream.Close();

            HttpWebResponse sendAbsolutiosResponse = (HttpWebResponse)sendAbsolutiosRequest.GetResponse();
            sendAbsolutiosResponse.Close();
        }

        /// <summary>
        /// Získá data uživatelského profilu z profilové stránky
        /// </summary>
        /// <param name="id">Id profilu uživatele</param>
        /// <returns>Uživatelský profil</returns>
        public Profile GetProfile(int id)
        {
            Uri uri = new Uri(string.Format(ProfileDetailUri, id));
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
            request.CookieContainer = CookieContainer;

            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            HtmlDocument doc = new HtmlDocument();
            doc.Load(response.GetResponseStream(), DefaultEncoding);

            Profile profile = new Profile();
            profile.Id = id;

            var messagesNodes = doc.DocumentNode.SelectNodes("//td[@class='guestblock']");
            if (messagesNodes != null) // no absolutions?
            {
                var messages = new List<PersonalMessage>();
                profile.PersonalMessages = messages;
                foreach (var messageNode in messagesNodes)
                {
                    PersonalMessage message = new PersonalMessage();
                    int? creatorId = null;
                    string creatorName;
                    var nickNode = messageNode.SelectSingleNode(".//span[@class='guestnick']");
                    if (nickNode != null)
                    {
                        var nickLinkNode = nickNode.SelectSingleNode(".//a");
                        creatorId = int.Parse(nickLinkNode.Attributes["href"].Value.Replace("profil.php?kdo=", string.Empty));
                        creatorName = nickLinkNode.InnerText.Trim();
                    }
                    else
                    {
                        creatorName = messageNode.SelectSingleNode(".//span[@class='guestnote']").InnerText.Trim();
                        //TODO: remove ( ) and parse email
                    }

                    message.Creator = new Profile();
                    message.Creator.Id = creatorId;
                    message.Creator.Name = creatorName;

                    //message.CreationDate = 
                    //message.Id =

                    message.Text = messageNode.SelectSingleNode(".//div[@class='guesttext']").InnerText;

                    messages.Add(message);
                }
            }
            return profile;
        }

        public void SendPersonalMessage(int profileId, string message)
        {
            if (!LoggedIn)
                throw new Exception("Not logged in");


            string postData = "proid=" + profileId;
            postData += ("&odid=" + LoggedUser.Id);
            postData += ("&odkoho=" + LoggedUser.Name);
            postData += ("&posta=" + "");
            postData += ("&sys=" + "0");
            postData += ("&kam=" + "osobní návštěvní knihy");
            postData += ("&body=" + message.Replace(" ", "+"));

            byte[] data = DefaultEncoding.GetBytes(postData);


            HttpWebRequest sendMessageRequest = (HttpWebRequest)WebRequest.Create(new Uri(SendPersonalMessageUri));
            sendMessageRequest.Referer = string.Format(SendPersonalMessageRefererUri, profileId);
            sendMessageRequest.Method = "POST";
            sendMessageRequest.ContentType = "application/x-www-form-urlencoded";
            sendMessageRequest.ContentLength = data.Length;
            sendMessageRequest.CookieContainer = CookieContainer;
            Stream newStream = sendMessageRequest.GetRequestStream();
            newStream.Write(data, 0, data.Length);
            newStream.Close();

            HttpWebResponse sendMessageResponse = (HttpWebResponse)sendMessageRequest.GetResponse();
            
            sendMessageResponse.Close();
        }

        public void DeletePersonalMessage(int personalMessageId)
        {
            if (!LoggedIn)
                throw new Exception("Not logged in");

            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(new Uri(string.Format(DeletePersonalMessageUri, personalMessageId)));
            request.CookieContainer = CookieContainer;

            HttpWebResponse response = (HttpWebResponse) request.GetResponse();
            response.Close();
        }
    }
}
